package jia.core.characters;

import jia.core.calculations.AttributeModifier;
import jia.core.calculations.GenerateStat;
import jia.core.items.Armor;
import jia.core.items.Item;
import jia.core.items.Weapon;
import jia.game.GenericFlags;
import org.apache.log4j.Logger;

import java.util.Collection;
import java.util.Hashtable;

/**
 * TODO:  Phase 1 - unarmored fighter with a weapon
 * TODO:  Phase 2 - armored fighter with a weapon
 * TODO:  Phase 3 - armored fighter with a base initiative value to add to an init roll
 * TODO:  Phase 4 - armored fighter whose race attribute affects armor class
 * TODO:  Phase 5 - character with specific class
 * TODO:  Phase 6 - character with magical item affecting a stat
 */
public class GameCharacter{
    private static final Logger log = Logger.getLogger(GameCharacter.class);
    protected long id;
    private boolean isDead = false;
    protected String characterName;
    protected String characterRace;
    protected int characterHP;
    
    protected int strength;
    protected int dexterity;
    protected int constitution;
    protected int intelligence;
    protected int wisdom;
    protected int charisma;
    
    protected int armorClass;
    protected int baseAttack;
    
    protected Item readiedWeapon;
    
    protected int baseInitiative;
    protected int baseSpeed;
    protected PlayerClass playerClass;
    protected Weapon weapon;
    protected Hashtable equippedArmor;
    
    protected String spritePath;
    
    /**
     */
    public GameCharacter(){
        characterName = "Unnamed";
        characterHP = 20;
        strength = 10;
        dexterity = 10;
        constitution = 10;
        intelligence = 10;
        wisdom = 10;
        charisma = 10;
        armorClass = 10;
        baseAttack = 0;
    }
    
    public GameCharacter(String name){
        characterName = name;
        /**
         * a characters hit points are determined by two criteria:  starting and level based.
         * a level 1 character starts out with the entire base amount (dependent on class) plus whatever
         * bonus they recieve from their constitution score.  From there if they have a racial bonus
         * (or penalty), that should also be figured in.
         */
        generateCharacterStats();
        characterHP = setHP();
        armorClass = setAC();
        baseAttack = setBaseAttack();
        baseInitiative = setBaseInit();
    }
    
    public GameCharacter(long newId, String name){
        id = newId;
        characterName = name;
        generateCharacterStats();
        characterHP = setHP();
        armorClass = setAC();
        baseAttack = setBaseAttack();
        baseInitiative = setBaseInit();
    }
    
    public GameCharacter(String name, PlayerClass playerClass, Race race){
        characterName = name;
        generateCharacterStats();
        
    }
    
    public GameCharacter(long id){
        //this will access a database and create the entire character from a record
        //based on the passed id.
    }
    
    //====================================================
    /**
     * @param name
     * @param hp
     */
    public GameCharacter(String name, int hp){
        generateCharacterStats();
        armorClass = setAC();
        characterName = name;
        characterHP = hp;
        baseInitiative = setBaseInit();
    }
    
    
    /**
     * Utility method that generates the stats for this GameCharacter whenever an instance
     * of it is created.
     */
    private void generateCharacterStats(){
        if (GenericFlags.debugMessages) {
            log.debug("Rolling Strength for " + getCharacterName());
        }
        strength = GenerateStat.rollStat();
        if (GenericFlags.debugMessages) {
            log.debug(getCharacterName() + " Strength was set to " + strength);
            log.debug("----------------------");
            log.debug("");
            
            log.debug("Rolling Dexterity for " + getCharacterName());
        }
        dexterity = GenerateStat.rollStat();
        if (GenericFlags.debugMessages) {
            log.debug(getCharacterName() + " Dexterity was set to " + dexterity);
            log.debug("----------------------");
            log.debug("");
            
            log.debug("Rolling Constitution for " + getCharacterName());
        }
        constitution = GenerateStat.rollStat();
        if (GenericFlags.debugMessages) {
            log.debug(getCharacterName() + " Constitution was set to " + constitution);
            log.debug("----------------------");
            log.debug("");
            
            log.debug("Rolling Intelligence for " + getCharacterName());
        }
        intelligence = GenerateStat.rollStat();
        if (GenericFlags.debugMessages) {
            log.debug(getCharacterName() + " Intelligence was set to " + intelligence);
            log.debug("----------------------");
            log.debug("");
            
            log.debug("Rolling Wisodom for " + getCharacterName());
        }
        wisdom = GenerateStat.rollStat();
        if (GenericFlags.debugMessages) {
            log.debug(getCharacterName() + " Wisodom was set to " + wisdom);
            log.debug("----------------------");
            log.debug("");
            
            log.debug("Rolling Charisma for " + getCharacterName());
        }
        charisma = GenerateStat.rollStat();
        if (GenericFlags.debugMessages) {
            log.debug(getCharacterName() + " Charisma was set to " + charisma);
            log.debug("----------------------");
            log.debug("");
        }
    }
    
    public String getCharacterName(){
        return characterName;
    }
    
    public int getBaseSpeed(){
        return baseSpeed;
    }
    
    public void setBaseSpeed(int baseSpeed){
        this.baseSpeed = baseSpeed;
    }
    
    public int getCharacterHP(){
        return characterHP;
    }
    
    public void setCharacterName(String name){
        this.characterName = name;
    }
    
    public void setCharacterHP(int hp){
        this.characterHP = hp;
    }
    
    public int getStrength(){
        return strength;
    }
    
    public int getStrengthMod(){
        return AttributeModifier.calculateMod(strength);
    }
    
    public void setStrength(int str){
        this.strength = str;
    }
    
    public int getDexterity(){
        return dexterity;
    }
    
    public int getDexterityMod(){
        return AttributeModifier.calculateMod(dexterity);
    }
    
    public void setDexterity(int dex){
        this.dexterity = dex;
    }
    
    public int getConstitution(){
        return constitution;
    }
    
    public int getConstitutionMod(){
        return AttributeModifier.calculateMod(constitution);
    }
    
    public void setConstitution(int con){
        this.constitution = con;
    }
    
    public int getIntelligence(){
        return intelligence;
    }
    
    public int getIntelligenceMod(){
        return AttributeModifier.calculateMod(intelligence);
    }
    
    public void setIntelligence(int intell){
        this.intelligence = intell;
    }
    
    public int getWisdom(){
        return wisdom;
    }
    
    public int getWisdomMod(){
        return AttributeModifier.calculateMod(wisdom);
    }
    
    public void setWisdom(int wis){
        this.wisdom = wis;
    }
    
    public int getCharisma(){
        return charisma;
    }
    
    public int getCharismaMod(){
        return AttributeModifier.calculateMod(charisma);
    }
    
    public void setCharisma(int newCharisma){
        this.charisma = newCharisma;
    }
    
    public int getArmorClass(){
        return (10 + getDexterityMod() + getArmorBonus());
    }
    
    public void setArmorClass(int armorClass){
        this.armorClass = armorClass;
    }
    
    public int getBaseAttack(){
        return baseAttack;
    }
    
    public void setBaseAttack(int baseAttack){
        this.baseAttack = baseAttack;
    }
    
    public Item getReadiedWeapon(){
        return readiedWeapon;
    }
    
    public void setReadiedWeapon(Item readiedWeapon){
        this.readiedWeapon = readiedWeapon;
    }
    
    public boolean getIsDead(){
        return isDead;
    }
    
    public void setIsDead(boolean dead){
        isDead = dead;
    }
    
    public int getBaseInitiative(){
        return baseInitiative;
    }
    
    public void setBaseInitiative(int baseInitiative){
        this.baseInitiative = baseInitiative;
    }
    
    public long getId(){
        return id;
    }
    
    public void setId(long id){
        this.id = id;
    }
    
    public boolean isDead(){
        return isDead;
    }
    
    public void setDead(boolean dead){
        isDead = dead;
    }
    
    public String getCharacterRace(){
        return characterRace;
    }
    
    public void setCharacterRace(String characterRace){
        this.characterRace = characterRace;
    }
    
    public PlayerClass getPlayerClass(){
        return playerClass;
    }
    
    public void setPlayerClass(PlayerClass playerClass){
        this.playerClass = playerClass;
    }
    
    public String getSpritePath(){
        return spritePath;
    }
    
    public void setSpritePath(String spritePath){
        this.spritePath = spritePath;
    }
    
    public Weapon getWeapon(){
        return weapon;
    }
    
    public void setWeapon(Weapon weapon){
        this.weapon = weapon;
    }
    
    /**
     * Sets the current characters hit points based upon a die roll and their constitution modifier
     *
     */
    public int setHP(){
        int hp = 0;
        try {
            int roll = 0;
            if (playerClass != null){
                roll = playerClass.getBaseHitDie();
            }else{
                roll = 10;
            }
            
            hp = roll + getConstitutionMod();
            
            //log.debug(characterState.getCharacter().getCharacterName() + "'s hit points have been set to " + roll + " plus modifier value of " + characterState.getCharacter().getConstitutionMod() + ", equalling " + characterState.getCharacter().getCharacterHP());
            
        } catch(Exception e) {
            if (GenericFlags.errorMessages){
                log.error(e.getMessage());
            }
        }
        
        return hp;
    }
    
    
    public int setAC(){
        int ac = 0;
        try {
            int baseAC = 10;
            ac = baseAC + getDexterityMod();
            if (equippedArmor.size() > 0){
                Collection armorItems = equippedArmor.values();
                for(Object armorItem : armorItems) {
                    Armor o = (Armor) armorItem;
                    ac = ac + o.getAcBonus();
                }
            }
        } catch(Exception e) {
            if (GenericFlags.errorMessages){
                log.error(e.getMessage());
            }
        }
        return ac;
    }
    
    public int setBaseAttack(){
        int ba = 0;
        try {
            ba = ba+getDexterityMod();
        } catch(Exception e) {
            if (GenericFlags.errorMessages){
                log.error(e.getMessage());
            }
        }
        return ba;
    }
    
    public int setBaseInit(){
        int bi = 0;
        try {
            bi = bi+getDexterityMod();
        } catch(Exception e) {
            if (GenericFlags.errorMessages){
                log.error(e.getMessage());
            }
        }
        return bi;
        
    }
    
    public Hashtable getEquippedArmor(){
        return equippedArmor;
    }
    
    public void setEquippedArmor(Hashtable equippedArmor){
        this.equippedArmor = equippedArmor;
    }
    
    public int getArmorBonus(){
        int retVal = 0;
        try {
            if (equippedArmor != null && equippedArmor.size() > 0){
                Collection armorItems = equippedArmor.values();
                for(Object armorItem : armorItems) {
                    Armor o = (Armor) armorItem;
                    retVal = retVal + o.getAcBonus();
                }
            }
        } catch(Exception e) {
            if (GenericFlags.errorMessages){
                log.error("Error getting armor bonus! - " + e.getMessage());
            }
        }
        return retVal;
    }
}


